package cron

import (
	"fmt"
	"github.com/pkg/errors"
	"github.com/robfig/cron/v3"
	"server/logger"
	"sync"
)

var (
	CRON *CronTab
)

type Cron struct {
	Spec   string `gorm:"column:spec;type:varchar(200)" json:"spec"`
	Switch bool   `gorm:"column:switch;type:bool;default:0" json:"switch"`
}

type CronTab struct {
	inner *cron.Cron
	ids   map[string]cron.EntryID
	mutex sync.Mutex
}

func NewCronTab() *CronTab {
	return &CronTab{
		inner: cron.New(),
		ids:   make(map[string]cron.EntryID),
	}
}

func (c *CronTab) IDS() []string {
	c.mutex.Lock()
	defer c.mutex.Unlock()
	ids := make([]string, 0, len(c.ids))
	invalidIDs := make([]string, 0)
	for sid, eid := range c.ids {
		if e := c.inner.Entry(eid); e.ID != eid {
			invalidIDs = append(invalidIDs, sid)
			continue
		}
		ids = append(ids, sid)
	}
	for _, id := range ids {
		delete(c.ids, id)
	}
	return ids
}

func (c *CronTab) Start() {
	c.inner.Start()
}

func (c *CronTab) Stop() {
	c.inner.Stop()
}

func (c *CronTab) AddByID(id, spec string, cmd cron.Job) error {
	c.mutex.Lock()
	defer c.mutex.Unlock()

	if _, ok := c.ids[id]; !ok {
		return errors.Errorf("crontab is exists")
	}
	eid, err := c.inner.AddJob(spec, cmd)
	if err != nil {
		return err
	}
	c.ids[id] = eid
	return nil
}

func (c *CronTab) DelByID(id string) {
	c.mutex.Lock()
	defer c.mutex.Unlock()

	eid, ok := c.ids[id]
	if !ok {
		return
	}
	c.inner.Remove(eid)
	delete(c.ids, id)
	logger.Info(fmt.Sprintf("取消定时任务%s成功", id))
}

func (c *CronTab) AddByFunc(id string, spec string, f func()) error {
	c.mutex.Lock()
	defer c.mutex.Unlock()

	if _, ok := c.ids[id]; ok {
		return errors.Errorf("crontab is exists")
	}
	eid, err := c.inner.AddFunc(spec, f)
	if err != nil {
		return err
	}
	c.ids[id] = eid
	return nil
}

func (c *CronTab) ISExists(id string) bool {
	if c != nil {
		_, exist := c.ids[id]
		return exist
	}
	return false
}

func (c *CronTab) GetAll() map[string]cron.EntryID {
	return c.ids
}
